package com.chinacoal.hr.levelimpl.utils;

import com.chinacoal.hr.levelimpl.model.DayLawItem;
import com.chinacoal.hr.levelimpl.model.DayLawManager;
import com.chinacoal.hr.levelimpl.service.HolidayLawsService;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author: YunTao.Li
 * @create: 2019-11-20 00:22
 * @description:
 **/
public class DateUtil {

    private static volatile DateUtil INSTANCE;

    private static HolidayLawsService holidayLawsService;

    private DateUtil() {
        holidayLawsService = SpringContextUtils.getBean(HolidayLawsService.class);
    }

    public static DateUtil getInstance() {
        if (null == INSTANCE) {
            synchronized (DateUtil.class) {
                if (null == INSTANCE) {
                    INSTANCE = new DateUtil();
                }
            }
        }
        return INSTANCE;
    }

    /**
     * 获得当前月的第一天
     *
     * @param format :
     * @return : java.lang.String
     * @author : YunTao.Li
     * @date : 2020/1/7 2020/1/7
     */
    public static String getFirstDayInMonth(SimpleDateFormat format) {

        Calendar c = Calendar.getInstance();
        c.add(Calendar.MONTH, 0);
        c.set(Calendar.DAY_OF_MONTH, 1);//设置为1号,当前日期既为本月第一天
        String monthfirst = format.format(c.getTime());
        return monthfirst;
    }

    /**
     * 获得某个月的第一天
     *
     * @param yrmonth :yyyy-MM
     * @return : java.lang.String
     * @author : YunTao.Li
     * @date : 2020/7/7 2020/7/7
     */
    public static Map<String, String> getFirstDayInMonth(String yrmonth) {
        String firstday, lastday;
        SimpleDateFormat monthFormat = new SimpleDateFormat("yyyy-MM");
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cale = Calendar.getInstance();
        Date date = null;
        try {
            date = monthFormat.parse(yrmonth);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        cale.setTime(date);

        // 获取前月的第一天
        cale.add(Calendar.MONTH, 0);
        cale.set(Calendar.DAY_OF_MONTH, 1);
        firstday = dateFormat.format(cale.getTime());

        cale.add(Calendar.MONTH, 1);
        cale.set(Calendar.DAY_OF_MONTH, 0);
        lastday = dateFormat.format(cale.getTime());

        Map<String, String> monthDayMap = new HashMap<String, String>();
        monthDayMap.put("firstday", firstday);
        monthDayMap.put("lastday", lastday);

        return monthDayMap;
    }

    /**
     * 获得一个月的最后一天yyyyMMdd
     *
     * @param format :
     * @return : java.lang.String
     * @author : YunTao.Li
     * @date : 2020/1/7 2020/1/7
     */
    public static String getLastDayInMonth(SimpleDateFormat format) {
        Calendar ca = Calendar.getInstance();
        ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));
        String monthlast = format.format(ca.getTime());
        System.out.println("===============last:" + monthlast);
        return monthlast;
    }

    /**
     * 获得日期的分割
     *
     * @param startDateStr :
     * @param endDateStr   :
     * @param splitDay     : 几天一分
     * @return : java.util.List<java.util.Map<java.lang.String,java.lang.String>>
     * @author : YunTao.Li
     * @date : 2020/1/7 2020/1/7
     */
    public static List<Map<String, String>> getDaySplit(String startDateStr, String endDateStr, int splitDay) throws Throwable {
        List<Map<String, String>> dateStrMapList = new ArrayList<Map<String, String>>();
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
        boolean flop = true;
        try {
            Calendar startCalendar = Calendar.getInstance();
            Date startDate = format.parse(startDateStr);
            startCalendar.setTime(startDate);

            Calendar endCalendar = Calendar.getInstance();
            Date endDate = format.parse(endDateStr);
            endCalendar.setTime(endDate);

            while (flop) {
                Map<String, String> dateStrMap = new HashMap<>();

                String splitStartDateStr = format.format(startCalendar.getTime());
                startCalendar.add(Calendar.DATE, splitDay);

                String splitEndDateStr = "";
                // 如果加因子后的start日期大于结束日期,则开始日期=结束日期,循环结束
                if (startCalendar.after(endCalendar)) {
                    splitEndDateStr = format.format(endCalendar.getTime());
                    flop = false;
                } else {
                    splitEndDateStr = format.format(startCalendar.getTime());
                }

                dateStrMap.put("startDateStr", splitStartDateStr);
                dateStrMap.put("endDateStr", splitEndDateStr);

                dateStrMapList.add(dateStrMap);
            }
        } catch (Throwable e) {
            e.printStackTrace();
            throw e;
        }

        return dateStrMapList;
    }

    /**
     * 比较两个时间，同一天返回0，不同天返回-1
     *
     * @param startDate :
     * @param endDate   :
     * @return : int
     * @author : YunTao.Li
     * @date : 2019/11/20 2019/11/20
     */
    public static int dateCompareTo(Date startDate, Date endDate) {
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(startDate);

        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(endDate);

        return cal1.compareTo(cal2);
    }

    /**
     * 单纯比较日历时间,比如20号到22号出差时间为2 + 1 = 3天
     *
     * @param startDate :
     * @param endDate   :
     * @return : int
     * @author : YunTao.Li
     * @date : 2020/1/7 2020/1/7
     */
    public static int getNatureDayMargin(Date startDate, Date endDate) {
        return getWorkDayMargin(startDate, endDate) + 1;
    }

    /**
     * 单纯比较日历时间,比如20号到22号出差时间为2天
     *
     * @param startDate :
     * @param endDate   :
     * @return : int
     * @author : YunTao.Li
     * @date : 2019/11/20 2019/11/20
     */
    public static int getWorkDayMargin(Date startDate, Date endDate) {
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(startDate);

        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(endDate);
        int day1 = cal1.get(Calendar.DAY_OF_YEAR);
        int day2 = cal2.get(Calendar.DAY_OF_YEAR);

        int year1 = cal1.get(Calendar.YEAR);
        int year2 = cal2.get(Calendar.YEAR);
        if (year1 != year2)   //同一年
        {
            int timeDistance = 0;
            for (int i = year1; i < year2; i++) {
                if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0)    //闰年
                {
                    timeDistance += 366;
                } else    //不是闰年
                {
                    timeDistance += 365;
                }
            }

            return timeDistance + (day2 - day1);
        } else    //不同年
        {
            return day2 - day1;
        }
    }

    /**
     * 获得自然日，如果开始当天是下午则减0.5天，如果结束当天是上午则减0.5天
     *
     * @param startDate     :
     * @param startTimeType :
     * @param endDate       :
     * @param endTimeType   :
     * @return : int
     * @author : YunTao.Li
     * @date : 2019/11/20 2019/11/20
     */
    public static int dateCompareToNatureDay(Date startDate, String startTimeType, Date endDate, String endTimeType) {
        int natureDay = DateUtil.getNatureDayMargin(startDate, endDate);

        if (StaticDicts.TIME_TYPE_AFTERNOON.equals(startTimeType)) { //如果出发日为下午，则减0.5天
            natureDay = new BigDecimal(natureDay).subtract(new BigDecimal(0.5)).intValue();
        }

        if (StaticDicts.TIME_TYPE_MORNING.equals(endTimeType)) { //如果返回日为上午，则减0.5天
            natureDay = new BigDecimal(natureDay).subtract(new BigDecimal(0.5)).intValue();
        }

        return natureDay;
    }

    /**
     * 判断是否是节假日
     *
     * @param day :
     * @return : boolean
     * @author : YunTao.Li
     * @date : 2019/12/27 2019/12/27
     */
    public boolean isHoliday(Date day) {
        boolean f = false;
        Calendar cal = Calendar.getInstance();
        cal.setTime(day);

        String hType = holidayLawsService.getHolidayHType(cal.getTime());
        // 周六 周日 默认为true
        if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
            f = true;

            // 如果是正常上班则返回false

            if (StaticDicts.HTYPE_WORKDAY.equals(hType)) {
                f = false;
            }
        } else {
            // 如果周一 周五 但是是法定假日则为true
            if (StaticDicts.HTYPE_HOLIDAY.equals(hType)) {
                f = true;
            }
        }

        // TODO: 判断表里是否是休息日
        return f;
    }

    /**
     * 根据开始日期,开始时段,结束日期,结束时段,计算经过了过少天多少个工作日
     *
     * @param startDate     :
     * @param startTimeType :
     * @param endDate       :
     * @param endTimeType   :
     * @return : com.chinacoal.hr.levelimpl.model.DayLawManager
     * @author : YunTao.Li
     * @date : 2019/12/27 2019/12/27
     */
    public static DayLawManager getDayLawManager(Date startDate, String startTimeType, Date endDate, String endTimeType) {

        List<DayLawItem> dayLawItems = new ArrayList<>();
        double natureDay = 0; //自然日
        double workDay = 0; //实际工作日
        Calendar calendar = Calendar.getInstance();
        Date currentDate = calendar.getTime(); //当前天
        DayLawItem item = new DayLawItem(); //构造item对象
        DayLawManager dayLawManager = new DayLawManager();

        if (dateCompareTo(startDate, endDate) == 0 && startTimeType.equals(endTimeType)) {
            natureDay = 0.5;
            workDay = 0.5;
            item.setTimeType("1");
            dayLawItems.add(item);

            dayLawManager.setWorkDay(workDay);
            dayLawManager.setNatureDay(natureDay);
            dayLawManager.setDayLawItems(dayLawItems);

            return dayLawManager;
        }

        /**
         * step1 : 获得从开始到结束日期的天数
         * */
        int natureDays = DateUtil.getNatureDayMargin(startDate, endDate);


        /**
         *  step2 : 循环遍历天数
         * */
        for (int i = 1; i <= natureDays; i++) {
            // 从开始日期机算，

            calendar.setTime(startDate);
            calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) + i - 1);

            // step2.1 : 首先计算日期，

            item.setDate(currentDate);

            String currentTimeType = "3"; //默认全天

            // 第一天上午出发
            if (i == 1 && ("1").equals(startTimeType)) {
                currentTimeType = "3";
            } else if (i == natureDays && ("2").equals(endTimeType)) { // 最后一天下午回来
                currentTimeType = "3";
            } else if (i == 1 && !("1").equals(startTimeType)) { // 第一天不是上午出发,那肯定下午出发了
                currentTimeType = "2";
            } else if (i == natureDays && !("2").equals(endTimeType)) { //最后一天不是下午返程那肯定上午返程了
                currentTimeType = "1";
            }

            /**
             * 时间计数开始
             * */

            // 判断是否是全天，如果是则工作日与自然日+1 ，如果不是则加完1后要减去0.5
            if (("3").equals(currentTimeType)) {
                natureDay++;
                workDay++;
            } else {
                natureDay++;
                workDay++;
                natureDay = natureDay - 0.5;
                workDay = workDay - 0.5;
            }

            // 判断这一天是不是休息日,如果是休息日则workday减少一天
            if (DateUtil.getInstance().isHoliday(currentDate)) {
                // 如果这一天是全天则-1,否则减0.5
                if (("3").equals(currentTimeType)) {
                    workDay = workDay - 1;
                } else {
                    workDay = workDay - 0.5;
                }
            }


            item.setTimeType(currentTimeType);
            dayLawItems.add(item);
        }

        dayLawManager.setWorkDay(workDay);
        dayLawManager.setNatureDay(natureDay);
        dayLawManager.setDayLawItems(dayLawItems);
        return dayLawManager;
    }

    /**
     * 获得当前年月的日期列表
     *
     * @param yrmonth : yyyy-DD
     * @return : java.util.List<java.lang.String>
     * @author : YunTao.Li
     * @date : 2020/7/9 2020/7/9
     */
    public static List<Date> getYrMonthDay(String yrmonth) throws Throwable {
        List<Date> yrmonthDateList = new ArrayList<Date>();
        SimpleDateFormat simple = new SimpleDateFormat("yyyy-MM");
        SimpleDateFormat simple2 = new SimpleDateFormat("yyyy-MM-dd");

        Date yrmonthDate = simple.parse(yrmonth);

        Calendar c = Calendar.getInstance();
        c.setTime(yrmonthDate);
        int lastDay = c.getActualMaximum(Calendar.DAY_OF_MONTH);
        for (int x = 1; x <= lastDay; x++, c.add(Calendar.DATE, 1)) {
            String dateStr = simple2.format(c.getTime());
            yrmonthDateList.add(c.getTime());
        }
        return yrmonthDateList;
    }

    /**
     * 获得当前年月的工作日列表
     *
     * @param yrmonth :
     * @return : java.util.List<java.util.Date>
     * @author : YunTao.Li
     * @date : 2020/7/20 2020/7/20
     */
    public synchronized static List<Date> getYrmonthWorkDayList(String yrmonth) throws Throwable {
        List<Date> workDayList = new ArrayList();
        getYrMonthDay(yrmonth).forEach(day -> {
            if (!DateUtil.getInstance().isHoliday(day)) {
                workDayList.add(day);
            }
        });
        return workDayList;
    }

    /**
     * 遍历年月，返回所有日期，且判断日期是否为假日
     *
     * @param yrmonth :
     * @return : java.util.List<java.util.Map>
     * @author : YunTao.Li
     * @date : 2020/7/9 2020/7/9
     */
    public static Map<Date, Boolean> getYrmonthDayMap(String yrmonth) throws Throwable {
        List<Date> list = getYrMonthDay(yrmonth);
        Map dayMap = new HashMap();
        for (Date d : list) {
            boolean f = DateUtil.getInstance().isHoliday(d);
            dayMap.put(d, f);
        }
        return dayMap;
    }

    /**
     * 获得年月中的工作日数量
     *
     * @param yrmonth :
     * @return : int
     * @author : YunTao.Li
     * @date : 2020/7/20 2020/7/20
     */
    public static int getYrmonthWorkDayCount(String yrmonth) throws Throwable {
        AtomicInteger count = new AtomicInteger();
        getYrmonthDayMap(yrmonth).forEach((k, v) -> {
            if (!v) {
                count.getAndIncrement();
            }
        });
        return count.get();
    }

    public static void main(String[] args) {
        try {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            Date beginDate = format.parse("2019-12-20");
            Date endDate = format.parse("2019-12-22");

            String str = getDayLawManager(beginDate, "1", endDate, "1").toString();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
